/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut
)]

use crate::common::*;

extern "C" {
    fn memcmp(_: *const libc::c_void, _: *const libc::c_void, _: libc::c_ulong) -> libc::c_int;
    fn strchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char;
    fn inet_pton(
        __af: libc::c_int,
        __cp: *const libc::c_char,
        __buf: *mut libc::c_void,
    ) -> libc::c_int;
    static mut sudoers_subsystem_ids: [libc::c_uint; 0];
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    fn sudo_strtonum(
        _: *const libc::c_char,
        _: libc::c_longlong,
        _: libc::c_longlong,
        _: *mut *const libc::c_char,
    ) -> libc::c_longlong;
    fn get_interfaces() -> *mut interface_list;
}

pub const PF_INET: libc::c_int = 2;
pub const AF_INET: libc::c_int = PF_INET;
pub const PF_INET6: libc::c_int = 10;
pub const AF_INET6: libc::c_int = PF_INET6;

#[derive(Copy, Clone)]
#[repr(C)]
pub union sudo_in_addr_un {
    pub ip4: in_addr,
    pub ip6: in6_addr,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct interface {
    pub entries: C2RustUnnamed_0,
    pub family: libc::c_uint,
    pub addr: sudo_in_addr_un,
    pub netmask: sudo_in_addr_un,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct C2RustUnnamed_0 {
    pub sle_next: *mut interface,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct interface_list {
    pub slh_first: *mut interface,
}

#[inline]
fn __bswap_32(mut __bsx: __uint32_t) -> __uint32_t {
    (__bsx & 0xff000000 as libc::c_uint) >> 24
        | (__bsx & 0xff0000 as libc::c_uint) >> 8
        | (__bsx & 0xff00 as libc::c_uint) << 8
        | (__bsx & 0xff as libc::c_uint) << 24
}
#[inline]
fn addr_matches_if(mut n: *const libc::c_char) -> bool {
    let mut addr: sudo_in_addr_un = sudo_in_addr_un {
        ip4: in_addr { s_addr: 0 },
    };
    let mut ifp: *mut interface = std::ptr::null_mut::<interface>();
    let mut j: libc::c_uint = 0;
    let mut family: libc::c_uint = 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_MATCH!());

        if inet_pton(
            AF_INET6,
            n,
            &mut addr.ip6 as *mut in6_addr as *mut libc::c_void,
        ) == 1
        {
            family = AF_INET6 as libc::c_uint;
        } else if inet_pton(
            AF_INET,
            n,
            &mut addr.ip4 as *mut in_addr as *mut libc::c_void,
        ) == 1
        {
            family = AF_INET as libc::c_uint;
        } else {
            debug_return_bool!(false);
        }

        ifp = (*get_interfaces()).slh_first;
        while !ifp.is_null() {
            if (*ifp).family == family {
                match family as libc::c_int {
                    AF_INET => {
                        if (*ifp).addr.ip4.s_addr == addr.ip4.s_addr
                            || (*ifp).addr.ip4.s_addr & (*ifp).netmask.ip4.s_addr == addr.ip4.s_addr
                        {
                            debug_return_bool!(true);
                        }
                    }
                    AF_INET6 => {
                        if memcmp(
                            ((*ifp).addr.ip6.__in6_u.__u6_addr8).as_mut_ptr()
                                as *const libc::c_void,
                            (addr.ip6.__in6_u.__u6_addr8).as_mut_ptr() as *const libc::c_void,
                            ::core::mem::size_of::<[uint8_t; 16]>() as libc::c_ulong,
                        ) == 0
                        {
                            debug_return_bool!(true);
                        }
                        j = 0 as libc::c_uint;
                        while (j as libc::c_ulong)
                            < ::core::mem::size_of::<[uint8_t; 16]>() as libc::c_ulong
                        {
                            if (*ifp).addr.ip6.__in6_u.__u6_addr8[j as usize] as libc::c_int
                                & (*ifp).netmask.ip6.__in6_u.__u6_addr8[j as usize] as libc::c_int
                                != addr.ip6.__in6_u.__u6_addr8[j as usize] as libc::c_int
                            {
                                break;
                            }
                            j = j.wrapping_add(1);
                        }
                        if j as libc::c_ulong
                            == ::core::mem::size_of::<[uint8_t; 16]>() as libc::c_ulong
                        {
                            debug_return_bool!(true);
                        }
                    }
                    _ => {}
                }
            }
        }

        debug_return_bool!(false);
    } //unsafe
}

fn addr_matches_if_netmask(mut n: *const libc::c_char, mut m: *const libc::c_char) -> bool {
    let mut i: libc::c_uint = 0;
    let mut addr: sudo_in_addr_un = sudo_in_addr_un {
        ip4: in_addr { s_addr: 0 },
    };
    let mut mask: sudo_in_addr_un = sudo_in_addr_un {
        ip4: in_addr { s_addr: 0 },
    };
    let mut ifp: *mut interface = std::ptr::null_mut::<interface>();
    let mut j: libc::c_uint = 0;
    let mut family: libc::c_uint = 0;
    let mut errstr: *const libc::c_char = std::ptr::null::<libc::c_char>();
    unsafe {
        debug_decl!(SUDOERS_DEBUG_MATCH!());

        if inet_pton(
            AF_INET6,
            n,
            &mut addr.ip6 as *mut in6_addr as *mut libc::c_void,
        ) == 1
        {
            family = AF_INET6 as libc::c_uint;
        } else if inet_pton(
            AF_INET,
            n,
            &mut addr.ip4 as *mut in_addr as *mut libc::c_void,
        ) == 1
        {
            family = AF_INET as libc::c_uint;
        } else {
            debug_return_bool!(false);
        }

        if family == AF_INET as libc::c_uint {
            if !(strchr(m, '.' as i32)).is_null() {
                if inet_pton(
                    AF_INET,
                    m,
                    &mut mask.ip4 as *mut in_addr as *mut libc::c_void,
                ) != 1
                {
                    sudo_debug_printf!(
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                        b"IPv4 netmask %s: %s\0" as *const u8 as *const libc::c_char,
                        m,
                        b"invalid value\0" as *const u8 as *const libc::c_char
                    );
                    debug_return_bool!(false);
                }
            } else {
                i = sudo_strtonum(
                    m,
                    1 as libc::c_longlong,
                    32 as libc::c_longlong,
                    &mut errstr,
                ) as libc::c_uint;
                if !errstr.is_null() {
                    sudo_debug_printf!(
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                        b"IPv4 netmask %s: %s\0" as *const u8 as *const libc::c_char,
                        m,
                        errstr
                    );
                    debug_return_bool!(false);
                }
                mask.ip4.s_addr = __bswap_32(
                    (0xffffffff as libc::c_uint) << (32 as libc::c_uint).wrapping_sub(i),
                );
            }
            addr.ip4.s_addr &= mask.ip4.s_addr;
        } else if inet_pton(
            AF_INET6,
            m,
            &mut mask.ip6 as *mut in6_addr as *mut libc::c_void,
        ) != 1
        {
            j = sudo_strtonum(
                m,
                1 as libc::c_longlong,
                128 as libc::c_longlong,
                &mut errstr,
            ) as libc::c_uint;
            if !errstr.is_null() {
                sudo_debug_printf!(
                    SUDO_DEBUG_ERROR | SUDO_DEBUG_LINENO,
                    b"IPv6 netmask %s: %s\0" as *const u8 as *const libc::c_char,
                    m,
                    errstr
                );
                debug_return_bool!(false);
            }
            i = 0 as libc::c_uint;
            while (i as libc::c_ulong) < ::core::mem::size_of::<[uint8_t; 16]>() as libc::c_ulong {
                if j < i.wrapping_mul(8 as libc::c_uint) {
                    mask.ip6.__in6_u.__u6_addr8[i as usize] = 0 as uint8_t;
                } else if i
                    .wrapping_mul(8 as libc::c_uint)
                    .wrapping_add(8 as libc::c_uint)
                    <= j
                {
                    mask.ip6.__in6_u.__u6_addr8[i as usize] = 0xff as uint8_t;
                } else {
                    mask.ip6.__in6_u.__u6_addr8[i as usize] =
                        (0xff00 >> j.wrapping_sub(i.wrapping_mul(8 as libc::c_uint))) as uint8_t;
                }
                addr.ip6.__in6_u.__u6_addr8[i as usize] = (addr.ip6.__in6_u.__u6_addr8[i as usize]
                    as libc::c_int
                    & mask.ip6.__in6_u.__u6_addr8[i as usize] as libc::c_int)
                    as uint8_t;
                i = i.wrapping_add(1);
            }
        }

        ifp = (*get_interfaces()).slh_first;
        while !ifp.is_null() {
            if (*ifp).family == family {
                match family as libc::c_int {
                    AF_INET => {
                        if (*ifp).addr.ip4.s_addr & mask.ip4.s_addr == addr.ip4.s_addr {
                            debug_return_bool!(true);
                        }
                    }
                    AF_INET6 => {
                        j = 0 as libc::c_uint;
                        while (j as libc::c_ulong)
                            < ::core::mem::size_of::<[uint8_t; 16]>() as libc::c_ulong
                        {
                            if (*ifp).addr.ip6.__in6_u.__u6_addr8[j as usize] as libc::c_int
                                & mask.ip6.__in6_u.__u6_addr8[j as usize] as libc::c_int
                                != addr.ip6.__in6_u.__u6_addr8[j as usize] as libc::c_int
                            {
                                break;
                            }
                            j = j.wrapping_add(1);
                        }
                        if j as libc::c_ulong
                            == ::core::mem::size_of::<[uint8_t; 16]>() as libc::c_ulong
                        {
                            debug_return_bool!(true);
                        }
                    }
                    _ => {}
                }
            }
        }

        debug_return_bool!(false);
    } //unsafe
}

/*
 * Returns true if "n" is one of our ip addresses or if
 * "n" is a network that we are on, else returns false.
 */
#[no_mangle]
pub fn addr_matches(mut n: *mut libc::c_char) -> bool {
    let mut m: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut rc: bool = false;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_MATCH!());

        /* If there's an explicit netmask, use it. */
        m = strchr(n, '/' as i32);
        if !m.is_null() {
            m = m.offset(1);
            *m = '\0' as i32 as libc::c_char;
            rc = addr_matches_if_netmask(n, m);
            *m.offset(-(1 as libc::c_int as isize)) = '/' as i32 as libc::c_char;
        } else {
            rc = addr_matches_if(n);
        }
        sudo_debug_printf!(
            SUDO_DEBUG_DEBUG | SUDO_DEBUG_LINENO,
            b"IP address %s matches local host: %s\0" as *const u8 as *const libc::c_char,
            n,
            if rc as libc::c_int != 0 {
                b"true\0" as *const u8 as *const libc::c_char
            } else {
                b"false\0" as *const u8 as *const libc::c_char
            }
        );
        debug_return_bool!(false);
    } //unsafe
}
